#include "napi/native_api.h"
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <vector>
#include <cstdint> // 包含BYTE的定义，通常定义为uint8_t
//#include <ohos_serial.h>

typedef uint8_t BYTE;
static void calculate_checksum(const uint8_t *data, size_t length, uint8_t *checksum) {
    *checksum = 0; // 初始化校验和为0
    for (size_t i = 0; i < length; ++i) {
        *checksum += data[i]; // 累加每个字节到校验和
    }
}
const char startByte1 = 0x01;
const char startByte2 = 0x42;

int FindStartIndex(const char *buffer, size_t bufferSize) {
    int startIndex = -1;

    // 检查缓冲区中是否有足够的字节来形成起始标识符
    if (bufferSize >= 2) {
        // 遍历缓冲区以查找起始标识符
        for (size_t i = 0; i < bufferSize - 1; ++i) {
            if (buffer[i] == startByte1 && buffer[i + 1] == startByte2) {
                startIndex = static_cast<int>(i);
                break; // 找到后退出循环
            }
        }
    }

    return startIndex;
}
std::string convertCharArrayToString(const char *buffer, size_t length) {
    // 使用std::string的构造函数将char数组转换为字符串
    std::string str(buffer, length);

    // 直接返回转换后的字符串
    return str;
}


// 查找数据包的结束位置
int FindEndIndex(const std::vector<BYTE> &buffer, int startIndex) {
    const BYTE endByte = 0x0D;

    // 从起始索引之后开始搜索结束标识符
    for (size_t i = static_cast<size_t>(startIndex); i < buffer.size(); ++i) {
        // 如果找到结束标识符
        if (buffer[i] == endByte) {
            // 返回结束标识符的索引
            return static_cast<int>(i);
        }
    }

    // 如果没有找到结束标识符，则返回-1
    return -1;
}

static uint32_t CalculateWeight(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5) {
    // 确保每个字节的高四位都是3，这可以通过与运算和加法实现
    x1 = (x1 & 0x0F) + 0x30;
    x2 = (x2 & 0x0F) + 0x30;
    x3 = (x3 & 0x0F) + 0x30;
    x4 = (x4 & 0x0F) + 0x30;
    x5 = (x5 & 0x0F) + 0x30;

    // 根据算法计算重量
    uint32_t weight = (x5 - 0x30) * 65536 + (x4 - 0x30) * 4096 + (x3 - 0x30) * 256 + (x2 - 0x30) * 16 + (x1 - 0x30);

    return weight;
}


static napi_value Add(napi_env env, napi_callback_info info) {
    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 - value1, &sum);

    return sum;
}
char buffer[1024];

static napi_value TestOpenjdq(napi_env env, napi_callback_info info) {

    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    int serial_port = open("/dev/ttyS3", O_RDWR | O_NOCTTY | O_NDELAY); // 串口设备文件，如/dev/ttyS0
    // int serial_port = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); // 串口设备文件，如/dev/ttyS0
    double a = 0;
    if (serial_port < 0) {
        // std::cerr << "无法打开串口" << std::endl;
        a = 2;
    } else {
        // std::cerr << "可以打开串口" << std::endl;
        a = 5;
    }

    struct termios tty;
  

    if (tcgetattr(serial_port, &tty) != 0) {
        // std::cerr << "无法获取串口属性" << std::endl;
        close(serial_port);
        a = 50;
    }

    /*
        //memset(&tty, 0, sizeof tty);
      cfsetospeed(&tty, B9600); // 设置输出波特率
      cfsetispeed(&tty, B9600); // 设置输入波特率

      tty.c_cflag &= ~PARENB;        // 不使用校验位
      tty.c_cflag &= ~CSTOPB;        // 使用1个停止位
      tty.c_cflag &= ~CSIZE;         // 清除数据位设置
      tty.c_cflag |= CS8;            // 设置8位数据位
      tty.c_cflag &= ~CRTSCTS;       // 禁用硬件流控制
      tty.c_cflag |= CREAD | CLOCAL; // 打开串口读取，忽略modem控制线

      tty.c_iflag &= ~(IXON | IXOFF | IXANY);         // 禁用软件流控制
      // tty.c_iflag |= (IXON | IXOFF);          // 启用
      tty.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式，不解释字符

      tty.c_oflag &= ~OPOST; // 原始输出模式，不解释字符

      tty.c_cc[VMIN] = 0;   // 读取时不阻塞
      tty.c_cc[VTIME] = 10; // 读取超时时间（十分之一秒）
  */

    tcgetattr(serial_port, &tty);
    cfsetispeed(&tty, B9600);
    cfsetospeed(&tty, B9600);
    tty.c_cflag |= (CLOCAL | CREAD);
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tcsetattr(serial_port, TCSANOW, &tty);
    
          if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
        // std::cerr << "无法设置串口属性" << std::endl;
        close(serial_port);
        return 0;
    }
    uint8_t data_to_send[8];
    if (value0 == 0) {
        // 赋值要发送的字节序列（不包括校验和）
        data_to_send[0] = 0x55;
        data_to_send[1] = 0x01;
        // 12吸合（开） 11断开（关）
        data_to_send[2] = 0x12;
        data_to_send[3] = 0x00;
        data_to_send[4] = 0x00;
        data_to_send[5] = 0x00;
        data_to_send[6] = 0x01;
        data_to_send[7] = 0x69;
    } else {
        // 赋值要发送的字节序列（不包括校验和）
        data_to_send[0] = 0x55;
        data_to_send[1] = 0x01;
        // 12吸合（开） 11断开（关）
        data_to_send[2] = 0x11;
        data_to_send[3] = 0x00;
        data_to_send[4] = 0x00;
        data_to_send[5] = 0x00;
        data_to_send[6] = 0x01;
        data_to_send[7] = 0x68;
    }
    /*if (value0 == 0) {
        // 赋值要发送的字节序列（不包括校验和）
        data_to_send[0] = 0x55;
        data_to_send[1] = 0x01;
        //12吸合（开） 11断开（关）
        data_to_send[2] = 0x12;
        data_to_send[3] = 0x00;
        data_to_send[4] = 0x00;
        data_to_send[5] = 0x00;
        data_to_send[6] = 0x01;
    } else {
        // 假设else块中也需要赋值相同的序列，否则您可以按照需要修改值
        data_to_send[0] = 0x55;
        data_to_send[1] = 0x01;
        // 12吸合（开） 11断开（关）
        data_to_send[2] = 0x11;
        data_to_send[3] = 0x00;
        data_to_send[4] = 0x00;
        data_to_send[5] = 0x00;
        data_to_send[6] = 0x01;
    }*/
    size_t data_length = sizeof(data_to_send); // 获取数组长度（不包括校验和）

    // 为校验和分配空间
    uint8_t checksum;

    // 计算校验和
    calculate_checksum(data_to_send, data_length, &checksum);

    // 将校验和添加到数据末尾
    data_to_send[data_length] = checksum;
    data_length += 1; // 更新数据长度，包括校验和

    // 发送数据
    ssize_t bytes_written = write(serial_port, data_to_send, data_length);

    if (bytes_written < 0) {
        // std::cerr << "发送数据失败" << std::endl;
        a = 100;
    } else {
        // std::cout << "发送数据成功，共发送 " << bytes_written << " 字节" << std::endl;
        a = 1;
    }
    //close(serial_port);

    /*        char buffer[256] = {0};
            ssize_t n = read(serial_port, buffer, sizeof(buffer) - 1); // 读取数据

            if (n < 0) {
                std::cerr << "读取串口失败" << std::endl;
            } else {
                std::cout << "从串口读取到数据: " << buffer << std::endl;
            }*/
        
    // close(serial_port);


    napi_value sum;
    napi_create_double(env, serial_port, &sum);

    return sum;
}
static napi_value SendWight(napi_env env, napi_callback_info info) {

    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    int serial_port = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); // 串口设备文件，如/dev/ttyS0
    double a = 0;
    if (serial_port < 0) {
        // std::cerr << "无法打开串口" << std::endl;
        a = 2;
    } else {
        // std::cerr << "可以打开串口" << std::endl;
        a = 5;
    }

    struct termios tty;
    memset(&tty, 0, sizeof tty);

    if (tcgetattr(serial_port, &tty) != 0) {
        // std::cerr << "无法获取串口属性" << std::endl;
        close(serial_port);
        a = 50;
    }

    cfsetospeed(&tty, B19200); // 设置输出波特率
    cfsetispeed(&tty, B19200); // 设置输入波特率

    tty.c_cflag &= ~PARENB;        // 不使用校验位
    tty.c_cflag &= ~CSTOPB;        // 使用1个停止位
    tty.c_cflag &= ~CSIZE;         // 清除数据位设置
    tty.c_cflag |= CS8;            // 设置8位数据位
    tty.c_cflag &= ~CRTSCTS;       // 禁用硬件流控制
    tty.c_cflag |= CREAD | CLOCAL; // 打开串口读取，忽略modem控制线

    tty.c_iflag &= ~(IXON | IXOFF | IXANY);         // 禁用软件流控制
    tty.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式，不解释字符

    tty.c_oflag &= ~OPOST; // 原始输出模式，不解释字符

    tty.c_cc[VMIN] = 0;   // 读取时不阻塞
    tty.c_cc[VTIME] = 10; // 读取超时时间（十分之一秒）

    if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
        // std::cerr << "无法设置串口属性" << std::endl;
        close(serial_port);
        return 0;
    }
    uint8_t data_to_send[5];
    data_to_send[0] = 0x01;
    data_to_send[1] = 0x42;
    data_to_send[2] = 0x3F;
    data_to_send[3] = 0x02;
    data_to_send[4] = 0x0D;
    /*if (value0 == 0) {
        // 赋值要发送的字节序列（不包括校验和）
        data_to_send[0] = 0x55;
        data_to_send[1] = 0x01;
        //12吸合（开） 11断开（关）
        data_to_send[2] = 0x12;
        data_to_send[3] = 0x00;
        data_to_send[4] = 0x00;
        data_to_send[5] = 0x00;
        data_to_send[6] = 0x01;
    } else {
        // 假设else块中也需要赋值相同的序列，否则您可以按照需要修改值
        data_to_send[0] = 0x55;
        data_to_send[1] = 0x01;
        // 12吸合（开） 11断开（关）
        data_to_send[2] = 0x11;
        data_to_send[3] = 0x00;
        data_to_send[4] = 0x00;
        data_to_send[5] = 0x00;
        data_to_send[6] = 0x01;
    }*/
    size_t data_length = sizeof(data_to_send); // 获取数组长度（不包括校验和）

    // 为校验和分配空间
    // uint8_t checksum;

    // 计算校验和
    // calculate_checksum(data_to_send, data_length, &checksum);

    // 将校验和添加到数据末尾
    // data_to_send[data_length] = checksum;
    // data_length += 1; // 更新数据长度，包括校验和

    // 发送数据
    /*ssize_t bytes_written = write(serial_port, data_to_send, data_length);

    if (bytes_written < 0) {
        // std::cerr << "发送数据失败" << std::endl;
        a = 100;
    } else {
        // std::cout << "发送数据成功，共发送 " << bytes_written << " 字节" << std::endl;
        a = 1;
    }*/
    // close(serial_port);
    // sleep(3);
    char buffer[10] = {0};
    ssize_t n = read(serial_port, buffer, sizeof(buffer) - 1); // 读取数据
    if (n < 0) {
        a = 1086;
        //std::cerr << "读取串口失败" << std::endl;
    } else {
        //std::cout << "从串口读取到数据: " << buffer << std::endl;
        a = 1081;
        //a = buffer[3];
    }
    a = CalculateWeight(buffer[2], buffer[3], buffer[4], buffer[5], buffer[6]);
    close(serial_port);
    std::string result = convertCharArrayToString(buffer, sizeof(buffer) - 1);

    // napi_value sum;
    // napi_create_double(env, a, &sum);

    napi_value sum;
    napi_status status;
    status = napi_create_string_utf8(env, buffer, strlen(buffer), &sum);
    napi_create_double(env, serial_port, &sum);
    //napi_create_string_utf8(env, buffer, &sum);

    return sum;
}
static napi_value ReadWight(napi_env env, napi_callback_info info) {

    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    //int serial_port = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); // 串口设备文件，如/dev/ttyS0
    int serial_port = value0; // 串口设备文件，如/dev/ttyS0
    double a = 0;
    if (serial_port < 0) {
        // std::cerr << "无法打开串口" << std::endl;
        a = 2;
    } else {
        // std::cerr << "可以打开串口" << std::endl;
        a = 5;
    }

    struct termios tty;
    

    if (tcgetattr(serial_port, &tty) != 0) {
        // std::cerr << "无法获取串口属性" << std::endl;
        close(serial_port);
        a = 50;
    }
    /*
     memset(&tty, 0, sizeof tty);
     cfsetospeed(&tty, B19200); // 设置输出波特率
     cfsetispeed(&tty, B19200); // 设置输入波特率

     tty.c_cflag &= ~PARENB;        // 不使用校验位
     tty.c_cflag &= ~CSTOPB;        // 使用1个停止位
     tty.c_cflag &= ~CSIZE;         // 清除数据位设置
     tty.c_cflag |= CS8;            // 设置8位数据位
     tty.c_cflag &= ~CRTSCTS;       // 禁用硬件流控制
     tty.c_cflag |= CREAD | CLOCAL; // 打开串口读取，忽略modem控制线

     tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制
     // tty.c_iflag |= (IXON | IXOFF);          // 启用
     tty.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式，不解释字符

     tty.c_oflag &= ~OPOST; // 原始输出模式，不解释字符

     tty.c_cc[VMIN] = 0;   // 读取时不阻塞
     tty.c_cc[VTIME] = 10; // 读取超时时间（十分之一秒）*/

    tcgetattr(serial_port, &tty);
    cfsetispeed(&tty, B9600);
    cfsetospeed(&tty, B9600);
    tty.c_cflag |= (CLOCAL | CREAD);
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tcsetattr(serial_port, TCSANOW, &tty);


    if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
        // std::cerr << "无法设置串口属性" << std::endl;
        close(serial_port);
        return 0;
    }

    uint8_t data_to_send[5];
    data_to_send[0] = 0x01;
    data_to_send[1] = 0x42;
    data_to_send[2] = 0x3F;
    data_to_send[3] = 0x02;
    data_to_send[4] = 0x0D;
    size_t data_length = sizeof(data_to_send); // 获取数组长度（不包括校验和）
    //ssize_t bytes_written = write(serial_port, data_to_send, data_length);

    char buffertemp[50] = {0}; // 假设最大读取256字节
    // DWORD bytesRead = 0;
   // while (true) {
        ssize_t n = read(serial_port, buffertemp, sizeof(buffertemp) - 1); // 读取数据
        /*std::vector<BYTE> vecBuffer(std::begin(buffertemp), std::end(buffertemp));

        for (int i = 0; i < n; i++) {
            //ss << std::setw(2) << std::setfill('0') << (int)buffer[i];
            //std::cout << (int)buffer[i]; // 原始数据显示
            buffer[i] = (int) buffertemp[i];

        }*/
        //int startIndex = FindStartIndex(buffertemp,n);
        a = CalculateWeight(buffertemp[2], buffertemp[3], buffertemp[4], buffertemp[5], buffertemp[6]);
        /*
                if (n < 0) {
                    a = 1086;
                    //return 0;
                    // std::cerr << "读取串口失败" << std::endl;
                } else {
                    int startIndex = FindStartIndex(vecBuffer);
                    if (startIndex == -1) {
                        break;
                    }
                    int endIndex = FindEndIndex(vecBuffer, startIndex);
                    if (endIndex == -1) {
                        break;
                    }
                    a = CalculateWeight(buffertemp[startIndex+2], buffertemp[startIndex+3], buffertemp[startIndex+4],
           buffertemp[startIndex+5], buffertemp[startIndex+6]); vecBuffer.erase(vecBuffer.begin(), vecBuffer.begin() +
           endIndex + 1); return 0;
                    // std::cout << "从串口读取到数据: " << buffer << std::endl;
                    // a = 1081;
                }*/
    // }
    // ssize_t n;
    

    /*n = read(serial_port, buffer, sizeof(buffer) - 1); // 读取数据
    a = CalculateWeight(buffer[2], buffer[3], buffer[4], buffer[5], buffer[6]);
    while ((n = read(serial_port, buffer, sizeof(buffer))) > 0) {
        // 丢弃读取到的数据，这里不需要做任何处理
        // 如果你想要看到丢弃了多少数据，可以打印 bytesRead
        // std::cout << "Discarded " << bytesRead << " bytes." << std::endl;
    }*/

        //close(serial_port);


        napi_value sum;
        napi_create_double(env, a, &sum);

        return sum;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"testOpenjdq", nullptr, TestOpenjdq, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"ReadWight", nullptr, ReadWight, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"SendWight", nullptr, SendWight, nullptr, nullptr, nullptr, napi_default, nullptr}};
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void *)0),
    .reserved = {0},
};


extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
